import type { Metadata } from 'next'; import Link from 'next/link'; import { notFound } from 'next/navigation'; import { requireUser } from '@/lib/auth/session'; import { getCollectionDetail, listCollections } from '@/lib/account/queries'; import { getDisplay } from '@/lib/account/display'; import { deleteCollectionAction, toggleCollectionPublicAction } from '@/lib/account/actions'; import { PageHeader, btnSecondary, btnDanger, btnPrimary } from '@/components/account/page-header'; import { SummaryStats, AllocationCards, ValueSourceBadge } from '@/components/account/portfolio-widgets'; import { LineChart } from '@/components/account/charts'; import { Card, CardHeader, Delta, EmptyState, Table, th, td, tdNum, Badge } from '@/components/ui/primitives'; import { fmtDate, fmtPct, confidenceLabel } from '@/lib/format'; import { EditCollectionForm } from '../create-form'; import { AddItemForm } from './add-item-form'; export const metadata: Metadata = { title: 'Collection', robots: { index: false } }; export default async function CollectionPage({ params, searchParams }: { params: Promise<{ id: string }>; searchParams: Promise> }) { const { id } = await params; const sp = await searchParams; const u = await requireUser(`/collections/${id}`); const detail = await getCollectionDetail(u.id, id); if (!detail) notFound(); const d = await getDisplay(); const { collection: c, summary: s, items, history } = detail; const others = (await listCollections(u.id)).filter((x) => x.collection.id !== id); const sort = sp.sort ?? 'value'; const rows = [...s.items].sort((a, b) => { if (sort === 'gain') return (b.gainPct ?? -Infinity) - (a.gainPct ?? -Infinity); if (sort === 'name') return a.title.localeCompare(b.title); if (sort === 'recent') return (items.find((i) => i.id === b.id)?.createdAt.getTime() ?? 0) - (items.find((i) => i.id === a.id)?.createdAt.getTime() ?? 0); return (b.valueUsd ?? -1) - (a.valueUsd ?? -1); }); const publicUrl = c.isPublic && u.handle && c.publicSlug ? `/u/${u.handle}/${c.publicSlug}` : null; return ( <> {c.color ? : null} {c.name} {c.isPublic ? public : private} } description={c.description ?? `${s.itemCount} item${s.itemCount === 1 ? '' : 's'} · created ${fmtDate(c.createdAt)}`} actions={ <> Add item Import CSV Insurance schedule CSV JSON } /> {s.valuedCount > 0 ? (
({ date: String(h.date), value: h.valueUsd * d.rate })) }, { name: 'Cost basis', points: history.map((h) => ({ date: String(h.date), value: h.costBasisUsd * d.rate })), color: 'var(--ri-fg-subtle)', dashed: true }]} height={180} formatY={(v) => d.money(v / d.rate, { compact: true })} />
) : null} {[ ['value', 'Value'], ['gain', 'Return'], ['recent', 'Recent'], ['name', 'Name'], ].map(([k, l]) => ( {l} ))} } /> {rows.length === 0 ? ( ) : ( {rows.map((i) => { const src = items.find((x) => x.id === i.id)!; return ( ); })}
Item Variant Qty Cost Value Gain 30d Source
{src.photos[0] || src.heroImageUrl ? ( // eslint-disable-next-line @next/next/no-img-element ) : ( )}
{i.title}

{i.categorySlug.replace(/_/g, ' ')} {i.acquiredAt ? ` · acquired ${i.acquiredAt}` : ''} {src.tags.length ? ` · ${src.tags.join(', ')}` : ''}

{src.variantLabel ?? (i.grader ? `${i.grader.toUpperCase()} ${i.grade ?? ''}` : src.condition ?? '—')} {i.quantity} {i.costUsd === null ? — : d.money(i.costUsd)} {i.valueUsd === null ? — : {d.money(i.valueUsd)}} {fmtPct(i.change30d)} Edit
)}
{c.isPublic ? ( publicUrl ? (

Public at{' '} {publicUrl}

) : (

Claim a public handle in{' '} profile settings {' '} to get a shareable URL.

) ) : null}

{others.length ? `Move items to another collection from each item page.` : 'Create another collection to move items between them.'}

); }